package com.groupbuying.currency.producer.service.impl;


import com.alibaba.fastjson.JSONObject;
import com.aliyun.openservices.ons.api.Message;
import com.aliyun.openservices.ons.api.Producer;
import com.aliyun.openservices.shade.com.alibaba.fastjson.JSON;
import com.aliyun.openservices.shade.com.alibaba.fastjson.serializer.SerializerFeature;
import com.groupbuying.currency.producer.connector.CustomerFeign;
import com.groupbuying.currency.producer.connector.PayInfoFeign;
import com.groupbuying.currency.producer.connector.SysconfigFeign;
import com.groupbuying.currency.producer.constants.CommonConstants;
import com.groupbuying.currency.producer.constants.CurrencyConstants;
import com.groupbuying.currency.producer.context.FilterContextHandler;
import com.groupbuying.currency.producer.domain.CurrencyCustomerDO;
import com.groupbuying.currency.producer.domain.CurrencyCustomerLogDO;
import com.groupbuying.currency.producer.dto.mq.TokenPayInfoPublishingToMq;
import com.groupbuying.currency.producer.dto.wx.currency.decrease.CurDecrNotifJsonData;
import com.groupbuying.currency.producer.dto.wx.currency.decrease.data.Data;
import com.groupbuying.currency.producer.dto.wx.currency.decrease.data.Keyword1;
import com.groupbuying.currency.producer.dto.wx.currency.decrease.data.Keyword2;
import com.groupbuying.currency.producer.dto.wx.currency.decrease.data.Keyword3;
import com.groupbuying.currency.producer.dto.wx.currency.decrease.data.Keyword4;
import com.groupbuying.currency.producer.dto.wx.currency.decrease.data.Keyword5;
import com.groupbuying.currency.producer.dto.wx.currency.decrease.data.Keyword6;
import com.groupbuying.currency.producer.mq.CurrencyMQConfig;
import com.groupbuying.currency.producer.mq.CurrencyMQProducer;
import com.groupbuying.currency.producer.service.CurrencyCustomerLogService;
import com.groupbuying.currency.producer.service.CurrencyCustomerService;
import com.groupbuying.currency.producer.service.CurrencyPayService;
import com.groupbuying.currency.producer.utils.BeanOrMapConvertUtils;
import com.groupbuying.currency.producer.utils.DateUtils;
import com.groupbuying.currency.producer.utils.HttpClientUtils;
import com.groupbuying.currency.producer.utils.Object2BigDecimal;
import com.groupbuying.currency.producer.utils.RedisUtils;
import com.groupbuying.currency.producer.utils.WeiXinUtils;
import com.groupbuying.currency.producer.utils.apiresult.ApiResult;
import com.groupbuying.currency.producer.utils.apiresult.ApiResultCode;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;


@Service
public class CurrencyPayServiceImpl implements CurrencyPayService {

  @Autowired
  private CurrencyCustomerService currencyCustomerService;

  @Autowired
  private CurrencyCustomerLogService currencyCustomerLogService;

  @Autowired
  private SysconfigFeign sysconfigFeign;

  @Autowired
  private CurrencyMQProducer currencyMQProducer;

  @Autowired
  private WeiXinUtils weiXinUtils;

  @Autowired
  private RedisUtils redisUtils;

  @Autowired
  private HttpClientUtils httpClientUtils;

  @Autowired
  private PayInfoFeign payInfoFeign;

  @Autowired
  private CustomerFeign customerFeign;

  @Override
  @Transactional(rollbackFor = Exception.class)
  public ApiResult doPayWithCurrency(Map<String, Object> mapParams) {

    /* >>>获取并校验参数与密码 */
    /* 1. 获取并校验参数 */
    Object tempParam = mapParams.get("password");
    String password = tempParam == null ? null : tempParam.toString();
    tempParam = mapParams.get("payId");
    String payId = tempParam == null ? null : tempParam.toString();
    tempParam = mapParams.get("payPrice");
    BigDecimal payPrice = tempParam == null ? null : Object2BigDecimal.getBigDecimal(tempParam);
    if (StringUtils.isEmpty(password) || StringUtils.isEmpty(payId) || payPrice == null) {
      return ApiResult.paramIsNull();
    }

    /* 2. 校验密码 */
    String customerId = FilterContextHandler.getUserID();
    if (!currencyCustomerService.checkCurrencyPwd(customerId, password)) {
      return ApiResult.failure(ApiResultCode.CURRENCY_PAYWORDERROR, "");
    }

    /* --------------------------------------------------------------------------------------------- */

    /* >>>根据传入数据更新积分账户 */
    /* 1、获取当前积分账户信息 */
    CurrencyCustomerDO currencyCustomerDO = currencyCustomerService.get(customerId);
    BigDecimal priceAfterDiscount = payPrice;
    BigDecimal useCurrency = currencyCustomerDO.getUseCurrency();
    BigDecimal totalCurrency = currencyCustomerDO.getTotalCurrency();

    /* 2. 如果打折后的积分小于可用积分或总积分，则消费失败，抛出异常“积分不足” */
    try {
      if (useCurrency.compareTo(priceAfterDiscount) == -1
          || totalCurrency.compareTo(priceAfterDiscount) == -1) {
        throw new Exception("积分不足");
      }
    } catch (Exception e) {
      e.printStackTrace();
    }

    /* 3. 根据对应积分消费规则计算扣除积分，更新积分账户 */
    currencyCustomerDO.setUseCurrency(useCurrency.subtract(priceAfterDiscount));
    currencyCustomerDO.setTotalCurrency(totalCurrency.subtract(priceAfterDiscount));
    currencyCustomerService.update(currencyCustomerDO);

    /* ----------------------------------------------------------------------------------------- */

    /* >>>记录积分日志 */
    CurrencyCustomerLogDO currencyCustomerLogDO = new CurrencyCustomerLogDO();
    currencyCustomerLogDO.setLogId(sysconfigFeign.createLogID());
    currencyCustomerLogDO.setActivityId(null);
    currencyCustomerLogDO.setCreateTime(DateUtils.format(new Date(), DateUtils.YMDHMS));
    currencyCustomerLogDO.setCurrencyCount(priceAfterDiscount);
    /* 碎银流向：01、活动；02、消费 */
    currencyCustomerLogDO.setCurrencySource(CurrencyConstants.CURRENCY_SOURCE_CONSUME);
    /* 碎银变化类型：01：增加：02减少，03：无变化 */
    currencyCustomerLogDO.setCurrencyType(CurrencyConstants.CURRENCY_TYPE_DECREASE);
    currencyCustomerLogDO.setCustomerId(customerId);
    currencyCustomerLogDO.setPayId(payId);
    /* 删除标记 1-未删除，0-已删除 */
    currencyCustomerLogDO.setDelFlag(CommonConstants.COMMON_FLAG_UNDEL);
    currencyCustomerLogDO.setCurrencyBalance(currencyCustomerDO.getTotalCurrency());
    currencyCustomerLogService.save(currencyCustomerLogDO);

    /* ----------------------------------------------------------------------------------------- */

    /* >>>通知支付中心 */
    /* 1、填充发送到支付中心的支付包体 */
    TokenPayInfoPublishingToMq tokenPayInfoPublishingToMq = new TokenPayInfoPublishingToMq();
    tokenPayInfoPublishingToMq.setCurPayLogId(currencyCustomerLogDO.getLogId());
    tokenPayInfoPublishingToMq.setCurPayRecvTime(currencyCustomerLogDO.getCreateTime());
    tokenPayInfoPublishingToMq.setCurPayStatus(CurrencyConstants.CURRENCY_PAY_SUCCESS);
    tokenPayInfoPublishingToMq.setPayCurrency(priceAfterDiscount);
    tokenPayInfoPublishingToMq.setPayId(payId);

    /* 2、发送信息到MQ */
    Producer producer = currencyMQProducer.getCurrencyMQProducer();
    try {
      Message message = new Message(
          CurrencyMQConfig.SEND_TO_PAY_TOPIC,
          CurrencyMQConfig.TAG_PAY_STATE_SUCCESS,
          JSON.toJSONString(BeanOrMapConvertUtils.objectToMap(tokenPayInfoPublishingToMq),
              SerializerFeature.DisableCircularReferenceDetect).getBytes());
      producer.send(message);
    } catch (Exception e) {
      e.printStackTrace();
    }

    /* ------------------------------------------------------------------------------------------ */

    /* >>>积分消费增加积分后，微信通知用户积分变动情况 */
    Map resultMap = new HashMap();
    try {

      /* 非积分消费增加积分后，微信通知用户积分变动情况 */
      /* 1. payId去重，防止前端重复提交 */
      if (redisUtils.isHasKey("doPayWithCurrency_" + payId)) {
        resultMap.put("errMsg", payId + " resubmit!");
        return ApiResult.failure(resultMap);
      }
      redisUtils.setKey("doPayWithCurrency_" + payId, "currencyChangePayId");

      /* 2. 获取微信调用access_token */
      String accessToken = weiXinUtils.getAccessToken();

      /* 3. 拼接微信小程序的发送地址 */
      String sendCurChangeUrl =
          "https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send"
              + "?access_token=" + accessToken;

      /* 4. 装配微信小程序的发送包体 */
      Map<String, String> map = payInfoFeign.getInfoForCurrencyWeChatRemind(payId);
      String orderId = map.get("orderId");
      String shopName = map.get("shopName");
      String payTime = map.get("payTime");
      String payMoney = map.get("payMoney");
      String formId = map.get("formId");
      String openiId = customerFeign.getOpenidByCustomerId(customerId);

      CurDecrNotifJsonData CurDecrNotifJsonData = new CurDecrNotifJsonData();
      CurDecrNotifJsonData.setTouser(openiId);
      CurDecrNotifJsonData.setFormId(formId);
      CurDecrNotifJsonData
          .setTemplateId("081kV2dQOvyo1pamufAgutV8v1wKZYDYmpVHCwc9gUw");
      Keyword1 keyword1 = new Keyword1();
      Keyword2 keyword2 = new Keyword2();
      Keyword3 keyword3 = new Keyword3();
      Keyword4 keyword4 = new Keyword4();
      Keyword5 keyword5 = new Keyword5();
      Keyword6 keyword6 = new Keyword6();
      keyword1.setValue(shopName);
      keyword2.setValue(orderId);
      keyword3.setValue(payMoney);
      keyword4.setValue("-" + priceAfterDiscount + "积分");
      keyword5.setValue(currencyCustomerDO.getUseCurrency() + "积分");
      keyword6.setValue(payTime);
      Data data = new Data(keyword1, keyword2, keyword3
          , keyword4, keyword5, keyword6);
      CurDecrNotifJsonData.setData(data);

      JSONObject jsonObject = (JSONObject) com.alibaba.fastjson.JSON.toJSON(CurDecrNotifJsonData);
      jsonObject.put("form_id", jsonObject.getString("formId"));
      jsonObject.put("page", "pages/home/index/index");
      jsonObject.put("template_id", jsonObject.getString("templateId"));
      jsonObject.remove("formId");
      jsonObject.remove("templateId");

      /* 4. 向微信服务器发送post请求，发送积分变动信息给用户 */
      JSONObject returnJsonObject = httpClientUtils
          .doPostSendJson(sendCurChangeUrl, jsonObject);
      String errmsg = returnJsonObject.getString("errmsg");
      String errcode = returnJsonObject.getString("errcode");

      if (!errcode.equals("0") || !errmsg.equals("ok")) {
        throw new Exception("发送积分变动消息失败！");
      }

    } catch (Exception e) {
      e.printStackTrace();
    }

    resultMap.put("payId", payId);
    return ApiResult.success(resultMap);
  }

}
